fix(devx): the two corpus walkers skip .cache/, so a console pin bump no longer reds on objectui's files - #15596
Conversation
… no longer reds on objectui's files (#15557) `scripts/build-console.sh` materialises objectui at the pinned SHA into `.cache/objectui-<sha>/` -- a whole foreign checkout, gitignored, that every console pin bump must create. Both repo-wide corpus walkers descended into it: `check-comment-mask-corpus` judged objectui's sources against this repo's masker and told the operator to pin a shape in `js-comment-mask.mjs`, and `check-agent-test-spelling` red on objectui's own AGENTS.md while its `deriveVitestScripts` walk let a foreign manifest widen the script names it judges here. CI never saw either, because the lint job does not build the console. Both walkers now carry `.cache` in the directory skip set they already keep, next to `node_modules` -- the same "not our source" class. Each self-test gains a control that plants the SAME BYTES inside and outside `.cache/` on a real temp tree: the copy inside never enters the corpus, the copy outside still reds, so the exclusion cannot become a mute button. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…rpus-walkers-skip-cache
|
ACCEPT — PM seat Reviewed against the three-dot diff
Dev's verification quoted (on Flipping ready + enabling auto-merge (MCP rate-limited since ~22:45Z — retried each tick with #15590, #15593, #15595). Fixes #15557. Generated by Claude Code |
Fixes #15557
scripts/build-console.shmaterialises objectui at the pinned SHA into.cache/objectui-SHA/— a whole foreign checkout, gitignored (.gitignore), that every console pin bump MUST create because the console cannot be built without it. Both repo-wide corpus walkers descended into it, so a pin bump read two reds against objectui's files, and one of them told the operator to go and pin a shape in this repo's masker.Direction 1 of the card, per the dispatch ruling: both walkers add
.cacheto the directory-name skip set they already keep — thenode_modulesclass, "not our source"..gitignore-honouring (direction 2) is a wider contract change and is not attempted here.Premise re-measured on a fresh
origin/maintree.cache/was absent on this container, so the behaviour was reproduced by planting one:.cache/objectui-probe/{AGENTS.md, apps/console/src/pages/Probe.tsx, package.json}, the three shapes a real build worktree carries. Same tree, same commit, nothing else changed between the columns; the probe was deleted before the commit andgit statusis clean..cache.cache, before the fix.cache, after the fixcollectSources()(comment-mask corpus).cache).cache)scannedFiles()(agent-test-spelling).cache/objectui-probe/AGENTS.md.cache)deriveVitestScripts()(same gate, second walk)test:probe-onlyentered the derived setpnpm check:agent-test-spelling.cache/objectui-probe/AGENTS.md:3The premise holds, and the measurement found one consequence the card did not name:
deriveVitestScriptswalks the same tree, so a foreign package's script names silently widened the set of names this gate judges in our own corpus — a false-red channel in the opposite direction from the one that was reported.The controls — both directions, in each gate's own fixture
Each
--self-testnow plants the SAME BYTES inside and outside.cache/on a real temp tree, so the only variable is location and the exclusion cannot become a mute button:check-comment-mask-corpus—src/probe.tsxand.cache/objectui-pin/src/probe.tsx, identical, against a masker that disagrees with the parser on them. The copy outside is collected and reds; the copy inside never enters the corpus; and the same bytes, compared directly withcompareFile, still disagree — so the exclusion is by location, not because those bytes happen to agree. 5 cases; the single battery's floor moves 12 → 17.check-agent-test-spelling— objectui's own instruction (pnpm --filter PKG test -- --run) in anAGENTS.mdunder.cache/objectui-pin/, plus a foreign manifest. Sweep is CLEAN, the walk never reaches the file, the manifest does not widen the derivation; the identical text one directory higher (vendor/objectui-pin/AGENTS.md) still reds and the finding names it. 5 cases in a new battery;SELF_TEST_BATTERY_FLOOR12 → 13.Ablation, trap-guarded, one set at a time, mutation confirmed on disk by anchor grep counts and restore proved by blob hash:
'.cache'fromSKIPPED_DIRECTORIES--self-testexit 1,3/17 self-test case(s) failed— the three new walk casesgit diff HEADempty; bloba2e698b9= HEAD blob'.cache'fromSKIP_DIRS--self-testexit 1,✗ check-agent-test-spelling --self-test -- 3 failure(s)— the three new.cachecasesgit diff HEADempty; blobb028549f= HEAD blobNeither gate is built: node runs
scripts/*.mjsfrom source, so there is nodist/leg to prove for either ablation.Importer census — who else reads these sets
SKIPPED_DIRECTORIESis exported, so every importer was enumerated:git grepoverscripts/,packages/,apps/forSKIPPED_DIRECTORIES/CORPUS_FLOOR/collectSourcesreturns no importer of this module's set — the othercollectSourceshits are unrelated local definitions (check-react-page-adapter-contract,tenant-audit-census,isystem-census, one plugin test).SKIP_DIRSis module-local and not exported. 43 scripts keep a private skip set of their own; no gate asserts agreement between them, andcheck-skill-identifier-livenesspins only its OWN set's contents. Independent evidence that no cross-walker parity gate exists:.gitis already inSKIPPED_DIRECTORIESand already absent from the listjs-comment-mask.mjs's header quotes, andmainis green.js-comment-mask.mjs's header quotes six directories as part of the 2026-08-21 measurement it records. That file is untouched (its PR is live); the corpus gate's own doc comment now says which of the two is the instrument and which is the history, so the claim it makes is true as written.scripts/pm/dispatch-gates.mjsis untouched. Both new fixture path literals sit insiderunSelfTestCases, whichCOMPOUND_ANCHOR_LEDGERalready classifies (['scripts/check-comment-mask-corpus.mjs', 'runSelfTestCases', false]), so they are masked from hint extraction;check:pm-dispatch-gatesis green.Verification — all at
4eaa5de8f(merge oforigin/maininto this branch), exit codes captured before any pipenode scripts/check-comment-mask-corpus.mjs --self-testAll 17 self-test cases passed.node scripts/check-comment-mask-corpus.mjs✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 5961 files, 0 disagree, 0 unparseable, 66.7s (comparator self-test: 17 cases pass).pnpm check:agent-test-spelling✓ check-agent-test-spelling: 0 violations — 450 file(s) · 6331 bare -- token(s) · 1454 launcher-rooted run(s) · 9 separator(s) JUDGED · 5 vitest-backed script name(s) derived from 81 manifest(s)pnpm check:pm-dispatch-gates✓ dispatch-gates self-test: 1445 cases pass.(no case edited; the dispatch expected 1415 — the merge oforigin/mainraised it)pnpm check:nul-bytescheck-nul-bytes: OK (scanned 7557 text file(s) … no raw ASCII control bytes)pnpm check:watch-hint-literal56 declaration(s) across 4 rostered name(s) … no unrostered spelling of the idiom in the treeThe family is
node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack(exit 0, 24 commands,--repo … checked against this checkout's 'origin' remote — it holds), re-derived after mergingorigin/main: the first derivation warned⚠️ STALE TREEand namedscripts/pm/dispatch-gates.mjsitself as changed in that range. The post-merge list is byte-identical, and every one of the 24 commands was run. Nothing NOT MEASURED: noexit 3, noPREREQUISITE NOT MET, noERR_MODULE_NOT_FOUND.Neither edited script has a vitest suite — their tests ARE their
--self-test, both of which were run and both of which served as the ablation instrument. The one file in the tree namingcheck-comment-mask-corpus.mjsin a test (packages/client/src/envelope-caller-census.test.ts) references it in prose only.Lint: a declared narrowing, not a whole-repo run.
eslint --no-inline-configover the two edited files: exit 0, and--format jsonreports 2 files, 0 errors, 0 warnings. The population is eslint's own flat config (both files matched it and were linted rather than ignored), and the config cannot move a verdict on any untouched file because this repo runs oneeslint.config.mjswhich "never enables type-aware linting (noparserOptions.project, no typed@typescript-eslintrules) for ANY file" — its own words, ateslint.config.mjs:326. CI runs the farm regardless.No changeset:
scripts/**only, nothing published from any package —skip-changesetapplied and read back.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code